package org.example.service;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.example.dto.LoanDataExcelDTO;
import org.example.entity.MallRepayPlan;
import org.example.entity.MallUserInfo;
import org.example.mapper.RepayPlanMapper;
import org.example.mapper.UserInfoMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static org.example.generator.DataGenerator.*;

/**
 * 贷款数据Excel导入服务（性能优化版）
 * 使用批量插入提升性能
 */
@Slf4j
@Service
public class LoanDataExcelImportService {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private RepayPlanMapper repayPlanMapper;
    
    // 批量处理配置 - 建议每批1000-5000条
    private static final int BATCH_SIZE = 2000;

    /**
     * 导入Excel文件 - 性能优化版
     * @param file Excel文件
     * @return 导入结果
     */
    public ImportResult importExcel(MultipartFile file) {
        long startTime = System.currentTimeMillis();
        ImportResult result = new ImportResult();
        List<String> errorMessages = new ArrayList<>();

        try {
            // 读取所有数据到内存
            final List<LoanDataExcelDTO> allData = new ArrayList<>();

            EasyExcel.read(file.getInputStream(), LoanDataExcelDTO.class, new ReadListener<LoanDataExcelDTO>() {
                @Override
                public void invoke(LoanDataExcelDTO data, AnalysisContext context) {
                    // 简单验证
                        String validationError = validateData(data);
                    if (validationError == null) {
                        allData.add(data);
                    } else {
                        errorMessages.add(String.format("第%d行: %s",
                            context.readRowHolder().getRowIndex() + 1, validationError));
                    }
                }

                @Override
                public void doAfterAllAnalysed(AnalysisContext context) {
                    log.info("Excel读取完成，共读取 {} 行数据", allData.size());
                }
            }).sheet().doRead();

            if (allData.isEmpty()) {
                result.setSuccess(false);
                result.setMessage("没有可导入的数据");
                result.setErrorMessages(errorMessages);
                return result;
            }

            // 按订单号分组
            Map<String, List<LoanDataExcelDTO>> orderGroupMap = allData.stream()
                .collect(Collectors.groupingBy(LoanDataExcelDTO::getOrderNumber));

            log.info("开始处理数据，共 {} 个订单", orderGroupMap.size());

            // 准备批量插入的数据
            List<MallUserInfo> userInfoList = new ArrayList<>(orderGroupMap.size());
            List<MallRepayPlan> repayPlanList = new ArrayList<>();

            // 处理每个订单组
            for (Map.Entry<String, List<LoanDataExcelDTO>> entry : orderGroupMap.entrySet()) {
                String orderNumber = entry.getKey();
                List<LoanDataExcelDTO> orderDataList = entry.getValue();
                
                try {
                    // 去重：按订单号和期数去重，只保留每个(订单号,期数)组合的第一条记录
                    Map<String, LoanDataExcelDTO> uniqueOrderPeriodMap = orderDataList.stream()
                        .collect(Collectors.toMap(
                            data -> orderNumber + "_" + data.getInstallmentCount(),
                            data -> data,
                            (existing, replacement) -> existing
                        ));
                    
                    // 获取去重后的数据列表，按期数排序
                    List<LoanDataExcelDTO> uniqueOrderDataList = uniqueOrderPeriodMap.values().stream()
                        .sorted(Comparator.comparing(LoanDataExcelDTO::getInstallmentCount))
                        .collect(Collectors.toList());
                    
                    // 计算该订单的最大期数作为loan_term
                    int maxPeriodNumber = uniqueOrderDataList.stream()
                        .mapToInt(LoanDataExcelDTO::getInstallmentCount)
                        .max()
                        .orElse(1);
                    
                    // 为每个订单创建一条用户信息记录
                    LoanDataExcelDTO firstData = uniqueOrderDataList.get(0);
                    MallUserInfo userInfo = convertToUserInfo(firstData, orderNumber, maxPeriodNumber);
                    if (userInfo != null) {
                        userInfoList.add(userInfo);
                    }
                    
                    // 为每个订单创建多条还款计划记录
                    if (userInfo != null) {
                        for (LoanDataExcelDTO data : uniqueOrderDataList) {
                            MallRepayPlan repayPlan = convertToRepayPlan(data, orderNumber, data.getInstallmentCount());
                            if (repayPlan != null) {
                                repayPlanList.add(repayPlan);
                            }
                        }
                    }
                    
                } catch (Exception e) {
                    errorMessages.add(String.format("订单号 %s 处理异常: %s", orderNumber, e.getMessage()));
                    log.error("处理订单数据异常，订单号: {}", orderNumber, e);
                }
            }
                    
            log.info("数据处理完成，开始批量插入数据库");
            log.info("用户信息: {} 条, 还款计划: {} 条", userInfoList.size(), repayPlanList.size());

            // 批量插入用户信息
            int userInfoInserted = batchInsertUserInfo(userInfoList);
            log.info("用户信息插入完成，共 {} 条", userInfoInserted);

            // 批量插入还款计划
            int repayPlanInserted = batchInsertRepayPlan(repayPlanList);
            log.info("还款计划插入完成，共 {} 条", repayPlanInserted);

            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;

            result.setSuccess(true);
            result.setMessage(String.format("导入完成，用户信息%d条，还款计划%d条，耗时%d秒",
                userInfoInserted, repayPlanInserted, duration / 1000));
            result.setErrorMessages(errorMessages);

            log.info("Excel导入完成，总耗时: {}ms, 处理速度: {}条/秒",
                duration, (userInfoInserted + repayPlanInserted) * 1000 / Math.max(duration, 1));

        } catch (IOException e) {
            log.error("读取Excel文件异常", e);
            result.setSuccess(false);
            result.setMessage("读取Excel文件失败: " + e.getMessage());
            return result;
        } catch (Exception e) {
            log.error("导入Excel异常", e);
            result.setSuccess(false);
            result.setMessage("导入失败: " + e.getMessage());
            return result;
        }

        return result;
    }

    /**
     * 批量插入用户信息
     */
    private int batchInsertUserInfo(List<MallUserInfo> userInfoList) {
        if (userInfoList == null || userInfoList.isEmpty()) {
            return 0;
        }

        int totalInserted = 0;
        int totalSize = userInfoList.size();

        // 分批插入
        for (int i = 0; i < totalSize; i += BATCH_SIZE) {
            int end = Math.min(i + BATCH_SIZE, totalSize);
            List<MallUserInfo> batch = userInfoList.subList(i, end);

            try {
                int inserted = userInfoMapper.insertBatch(batch);
                totalInserted += inserted;
                log.debug("批量插入用户信息: {}/{}", end, totalSize);
            } catch (Exception e) {
                log.error("批量插入用户信息失败，批次: {}-{}", i, end, e);
                throw new RuntimeException("批量插入用户信息失败", e);
            }
        }

        return totalInserted;
    }

    /**
     * 批量插入还款计划
     */
    private int batchInsertRepayPlan(List<MallRepayPlan> repayPlanList) {
        if (repayPlanList == null || repayPlanList.isEmpty()) {
            return 0;
        }

        int totalInserted = 0;
        int totalSize = repayPlanList.size();

        // 分批插入
        for (int i = 0; i < totalSize; i += BATCH_SIZE) {
            int end = Math.min(i + BATCH_SIZE, totalSize);
            List<MallRepayPlan> batch = repayPlanList.subList(i, end);

            try {
                int inserted = repayPlanMapper.insertBatch(batch);
                totalInserted += inserted;
                log.debug("批量插入还款计划: {}/{}", end, totalSize);
            } catch (Exception e) {
                log.error("批量插入还款计划失败，批次: {}-{}", i, end, e);
                throw new RuntimeException("批量插入还款计划失败", e);
            }
        }

        return totalInserted;
    }

    /**
     * 数据验证
     */
    private String validateData(LoanDataExcelDTO data) {
        if (data.getInstallmentCount() == null) {
            return "期数不能为空";
        }
        if (data.getOrderNumber() == null || data.getOrderNumber().trim().isEmpty()) {
            return "订单号不能为空";
        }
        return null;
    }

    /**
     * 转换为用户信息实体对象
     */
    private MallUserInfo convertToUserInfo(LoanDataExcelDTO dto, String orderNumber, int loanTerm) {
        MallUserInfo entity = new MallUserInfo();
        entity.setOrderNumber(dto.getOrderNumber());
        entity.setLoanTime(dto.getLoanTime());
        entity.setLoanAmount(dto.getLoanAmount());
        entity.setLoanTerm(String.valueOf(loanTerm));
        entity.setInstallmentCount(loanTerm);
        entity.setShippingProvince(dto.getShippingProvince());
        entity.setShippingCity(dto.getShippingCity());
        entity.setShippingDistrict(dto.getShippingDistrict());
        entity.setMonthlyIncome(dto.getMonthlyIncome());
        
        // 性别转换
        if (dto.getGender() != null && dto.getGender() == 0) {
            entity.setGender("女");
        } else {
            entity.setGender("男");
        }
        
        entity.setBirthday(dto.getBirthday());
        
        // 学历转换
        if (dto.getEducation() != null) {
            entity.setEducation(convertEducation(dto.getEducation()));
        }
        
        // 婚姻状况转换
        if (dto.getMaritalStatus() != null) {
            entity.setMaritalStatus(convertMaritalStatus(dto.getMaritalStatus()));
        }
        
        entity.setSesameScore(dto.getSesameScore());
        entity.setCreateTime(LocalDateTime.now());
        entity.setUpdateTime(LocalDateTime.now());
        entity.setAge(dto.getBirthday() != null ? Period.between(dto.getBirthday(), LocalDate.now()).getYears() : null);

        // 生成脱敏姓名
        entity.setUserName(generateMaskedName());

        // 生成脱敏手机号
        entity.setUserPhone(generateMaskedPhone());

        // 生成脱敏身份证号
        String code = CITY_CODE_MAP.get(entity.getShippingCity());
        if (StringUtils.isBlank(code)) {
            code = "110000";
        }
        entity.setUserIdNo(generateMaskedIdNo(code, entity.getGender()));
        
        return entity;
    }

    /**
     * 转换为还款计划实体对象
     */
    private MallRepayPlan convertToRepayPlan(LoanDataExcelDTO dto, String orderNumber, int periodNumber) {
        MallRepayPlan entity = new MallRepayPlan();
        entity.setOrderNumber(orderNumber);
        entity.setPeriodNumber(dto.getInstallmentCount());
        entity.setDueTime(dto.getDueTime());
        
        LocalDateTime targetDate = LocalDateTime.of(2025, 9, 30, 23, 59, 59);
        int status = dto.getDueTime().isBefore(targetDate) ? 2 : 0;
        
        // 取消的订单
        if (null != dto.getRepayStatus() && dto.getRepayStatus() == -1) {
            if (status == 2) {
        entity.setActualRepayTime(dto.getDueTime());
            } else {
                entity.setActualRepayTime(null);
            }
        entity.setRepayStatus(status);
            entity.setOverdueDays(0);
        } else if (null != dto.getRepayStatus() && dto.getRepayStatus() == 2 && null == dto.getActualRepayTime()) {
            entity.setActualRepayTime(dto.getDueTime());
            entity.setOverdueDays(0);
            entity.setRepayStatus(2);
        } else {
            entity.setActualRepayTime(dto.getActualRepayTime());
            entity.setRepayStatus(dto.getRepayStatus());
            entity.setOverdueDays(dto.getOverdueDays() != null ? dto.getOverdueDays() : 0);
        }

        entity.setPrincipalReceivable(dto.getPrincipalReceivable());
        entity.setCreateTime(LocalDateTime.now());
        entity.setUpdateTime(LocalDateTime.now());
        
        return entity;
    }
    
    /**
     * 转换学历编码为实际值
     */
    private String convertEducation(String code) {
        if (code == null) return "未知";
        switch (code) {
            case "10": return "研究生";
            case "20": return "本科";
            case "30": return "大专";
            case "40": return "中专";
            case "50": return "技术学校";
            case "60": return "高中";
            case "70": return "初中";
            case "80": return "小学及以下";
            case "99": return "未知";
            default: return "大专";
        }
    }
    
    /**
     * 转换婚姻状况编码为实际值
     */
    private String convertMaritalStatus(String code) {
        if (code == null) return "未婚";
        switch (code) {
            case "1": return "未婚";
            case "2": return "已婚";
            case "3": return "离异";
            case "4": return "丧偶";
            default: return "未婚";
        }
    }

    /**
     * 导入结果类
     */
    public static class ImportResult {
        private boolean success;
        private String message;
        private List<String> errorMessages = new ArrayList<>();

        public boolean isSuccess() {
            return success;
        }

        public void setSuccess(boolean success) {
            this.success = success;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }

        public List<String> getErrorMessages() {
            return errorMessages;
        }

        public void setErrorMessages(List<String> errorMessages) {
            this.errorMessages = errorMessages;
        }
    }
}
